package dispatcher;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Workbook;


import business.CellXLEW;
import business.CompanyPoll;
import business.Country;
import business.CoverDefinition;
import business.LocalMenu;
import business.MiningItem;
import business.Poll;
import business.PollValue;
import business.SendValidationResult;

import services.CompanyService;
import services.NotificationsService;
import services.PollService;
import services.ValidationService;
import utils.MyBase64;
import utils.POIUtils;
import utils.Utils;
import utils.ZipUsingJavaUtil;
import exceptions.ExDBException;

public class ExecuteAction extends HttpServlet {

	private static final String DOWNLOAD_DIRECTORY = "download";
	private static final String UPLOAD_DIRECTORY = "upload";
	private static final String TEMP_DIRECTORY = "temp";
	private static final String PACK_NAME = "Paquete de Encuestas";

	static Logger log = Logger.getLogger(ExecuteAction.class);
	
	private static final long serialVersionUID = 1L;

	private static final String ACTION_VALIDATE = "validate";
	private static final String ACTION_SEND = "send";
	private static final String ACTION_REJECT = "reject";
	private static final String ACTION_APRROVE = "approve";
	private static final String ACTION_REGIONALIZE = "regionalize";
	private static final String ACTION_DOWNLOAD_POLL = "downloadPoll";
	private static final String ACTION_UPLOAD_POLL = "uploadPoll";
	
	private Long sessionUserID = null;
	
	int i = 0;
	
	protected void executeAction(HttpServletRequest req, HttpServletResponse resp) throws IOException
	{
		PollService pollService = null;
		ValidationService validationService = null;
		NotificationsService notificationsService = null;
		CompanyService companyService = null;
		
		String templateFilePath = this.getServletContext().getRealPath(String.valueOf(File.separatorChar)) + "mail.html";
		
		HttpSession session = req.getSession(true);
		Object userID = session.getAttribute("userID");
		Object sessionCompanyCampaign = session.getAttribute("companyCampaign");
		
		String action = req.getParameter("action");
		
		if(userID == null || userID.toString().trim().length() == 0)
		{
			resp.sendRedirect("./login?option=" + MyBase64.encode(Login.NO_SESSION.getBytes()));
		}
		else
		{
			sessionUserID = (Long)userID; 
			Long companyCampaignID = null;
			if(sessionCompanyCampaign != null)
			{
				companyCampaignID = (Long) sessionCompanyCampaign;	
			}
			else if(req.getParameter("id") != null)
			{
				companyCampaignID = Long.valueOf(req.getParameter("id"));
			}			
			pollService = new PollService();
			notificationsService = new NotificationsService();
			companyService = new CompanyService();
			
			if(action.equals(ACTION_VALIDATE))
			{
				try {
					validationService = new ValidationService();
					validationService.validatePollsByCompanyCampaign(companyCampaignID);
					String page = "./validationGrid";
//					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_SUCCESS,
//							"Se validaron correctamente todos los formularios de la encuesta.",PollService.FORM_STATUS_VALIDATED_OK,"ALL");
					resp.sendRedirect(page);
				} catch (Exception e) {
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_ERROR,
							e.getMessage());
					resp.sendRedirect(page);
				}
			}
			else if(action.equals(ACTION_SEND))
			{
				try {
					validationService = new ValidationService();
					String page = null;
					SendValidationResult result = validationService.sendPollsByCompanyCampaign(companyCampaignID);
					notificationsService.sendNotificationStatusChange(templateFilePath, companyService.getCompanyCampaign(companyCampaignID), pollService.getPollStatusByID(PollService.POLL_STATUS_PENDING_REVIEW));

					if(result.isValid())
					{
//						pollService.updatePollAndFormStatus(companyCampaignID, PollService.POLL_STATUS_PENDING_REVIEW,PollService.FORM_STATUS_PENDING_REVIEW);
						page = Utils.getMessagePage(Utils.MESSAGE_TYPE_SUCCESS,
								"La encuesta ha sido enviada al usuario revisor.",
								PollService.POLL_STATUS_PENDING_REVIEW,
								PollService.FORM_STATUS_PENDING_REVIEW, PollService.ALL_FORMS_SUFIX);
					}
					else
					{
						page = Utils.getMessagePage(Utils.MESSAGE_TYPE_ERROR, "No se puede enviar la encuesta. Tiene " + result.getErrorsCount() +
								" errores y " + result.getWarningsCount() + " advertencias sin comentarios.");
					}					
					resp.sendRedirect(page);
				} catch (ExDBException e) {
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_WARNING,
							e.getMessage());
					resp.sendRedirect(page);
				}
			}
			else if(action.equals(ACTION_REJECT))
			{
				try {
					pollService.updatePollAndFormStatus(companyCampaignID, PollService.POLL_STATUS_REJECTED,PollService.FORM_STATUS_REJECTED);
//					pollService.updatePollStatus(companyCampaignID, PollService.POLL_STATUS_REJECTED);
					notificationsService.sendNotificationStatusChange(templateFilePath, companyService.getCompanyCampaign(companyCampaignID), pollService.getPollStatusByID(PollService.POLL_STATUS_REJECTED));
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_SUCCESS,
							"La encuesta ha sido rechazada.",
							PollService.POLL_STATUS_REJECTED,
							PollService.FORM_STATUS_REJECTED, PollService.ALL_FORMS_SUFIX);
					
					resp.sendRedirect(page);
				} catch (ExDBException e) {
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_ERROR,
							e.getMessage());
					resp.sendRedirect(page);
				}
			}
			else if(action.equals(ACTION_APRROVE))
			{
				try {
					pollService.updatePollAndFormStatus(companyCampaignID, PollService.POLL_STATUS_APPROVED,PollService.FORM_STATUS_APPROVED);
					notificationsService.sendNotificationStatusChange(templateFilePath, companyService.getCompanyCampaign(companyCampaignID), pollService.getPollStatusByID(PollService.POLL_STATUS_APPROVED));
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_SUCCESS,
							"La encuesta ha sido aprobada.",
							PollService.POLL_STATUS_APPROVED,
							PollService.FORM_STATUS_APPROVED, PollService.ALL_FORMS_SUFIX);
					resp.sendRedirect(page);
				} catch (ExDBException e) {
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_ERROR,
							e.getMessage());
					resp.sendRedirect(page);
				}
			}
			else if(action.equals(ACTION_REGIONALIZE))
			{
				try {
					pollService.regionalize(companyCampaignID);
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_SUCCESS,"Se ha regionalizado correctamente.");
					resp.sendRedirect(page);
				} catch (Exception e) {
					log.error("*** Error en Regionalización *** ");
					log.error(Utils.getStackTrace(e));
					log.error("*** --- *** ");					
					String page = Utils.getMessagePage(Utils.MESSAGE_TYPE_ERROR, "Se ha producido un error al regionalizar.");
					resp.sendRedirect(page);
				}
			}
			else if(action.equals(ACTION_DOWNLOAD_POLL))
			{
				File zipFile = getPackage(companyCampaignID);

				resp.setContentType("application/force-download");
				resp.setContentLength((int)zipFile.length());
				resp.setHeader("Content-Transfer-Encoding", "binary");
				resp.setHeader("Content-Disposition","attachment; filename=\"" + "Paquete de Encuestas.zip\"");
				
				InputStream is = new FileInputStream(zipFile);
				
				int read = 0;
				byte[] bytes = new byte[1024];
				OutputStream os = resp.getOutputStream();
				while ((read = is.read(bytes)) != -1) {
					os.write(bytes, 0, read);
				}
				os.flush();
				os.close();
			}
			else if(action.equals(ACTION_UPLOAD_POLL))
			{
				validationService = new ValidationService();
				String page = null;				
				try {
					
					ServletFileUpload upload = new ServletFileUpload();
					FileItemIterator iter = upload.getItemIterator(req);
					while (iter.hasNext()) {
					    FileItemStream item = iter.next();
					    if (item.isFormField()) {
			                String fieldname = item.getFieldName();
			                if(fieldname.equals("id"))
			                {
			                	companyCampaignID = Long.valueOf(Utils.getParameterValue(item));
			                }
			            } else {
			                String filename = FilenameUtils.getName(item.getName());			                
			                if(filename != null && filename.endsWith(".zip"))
							{
			                	InputStream openStream = item.openStream();
				                byte[] data = IOUtils.toByteArray(openStream);
				                
				                String tempPath = this.getServletContext().getRealPath(
				        				String.valueOf(File.separatorChar))
				        				+ TEMP_DIRECTORY
				        				+ File.separatorChar
				        				+ UPLOAD_DIRECTORY
				        				+ File.separatorChar;
				                File tempDir = new File(tempPath);
				        		if(tempDir.exists() || tempDir.isDirectory())
				        		{
				        			cleanTempDirectory(tempDir);
				        		}
				        		
				                Date date = new Date();
					            File temportal = new File(tempPath + date.getTime() + filename);
					            FileUtils.writeByteArrayToFile(temportal, data);
					             
					            File unzipDir = unzipPolls(temportal.getAbsolutePath());
					            pollService.processForms(unzipDir, companyCampaignID);
					            validationService.validatePollsByCompanyCampaign(companyCampaignID);
//					            processForms(unzipDir,companyCampaignID);
					            page = Utils.getAjaxParams(Utils.MESSAGE_TYPE_SUCCESS,"Encuestas procesadas correctamente.");
							}
							else
							{
								page = Utils.getAjaxParams(Utils.MESSAGE_TYPE_ERROR,"El archivo debe ser '.zip'");
								break;
							}
			            }
					}
			    } catch (Exception e) {
			       e.printStackTrace();
			       page = Utils.getAjaxParams(Utils.MESSAGE_TYPE_ERROR,e.getMessage());
			    }
			    
				PrintWriter out = resp.getWriter();
				if(page == null)
				{
					page = Utils.getAjaxParams(Utils.MESSAGE_TYPE_ERROR,"Ocurri� un error al procesar la solicitud, intente nuevamente.");
				}
				out.print(page);
			}
		}
	}
	
	@SuppressWarnings("unused")
	private void processForms(File dirFile,Long companyCampaignID)
	{
		String localName = dirFile.getName();
		Long localID = null;
		if(localName.trim().startsWith("Local "))
		{
			localID = Long.valueOf(localName.substring(6,localName.length()));
		}
		File[] unzipFiles = dirFile.listFiles();
		for(File currentUnzipFile : unzipFiles)
		{
			if(currentUnzipFile.isDirectory())
			{
				processForms(currentUnzipFile,companyCampaignID);
			}
			else
			{
				if(localID == null)
				{
					localID = Long.valueOf(0);
				}
				String pollName = currentUnzipFile.getName();
				processForm(currentUnzipFile,companyCampaignID,pollName,localID);
			}
		}
		try {
			new PollService().execSum(companyCampaignID);
			//TODO MENSAJE QUE SALIO TODOO BIEN
		} catch (Exception e) {
			//TODO MENSAJE QUE SALIO TODOO MAL
			e.printStackTrace();
		}
	}
	
	private File unzipPolls(String zipFile)
	{
		String tempPath = this.getServletContext().getRealPath(
				String.valueOf(File.separatorChar))
				+ TEMP_DIRECTORY
				+ File.separatorChar
				+ UPLOAD_DIRECTORY
				+ File.separatorChar;
		
		Date date = new Date();
		File tempDir = new File(tempPath);
		if(tempDir.exists() || tempDir.isDirectory())
		{
			String unzipDir = tempDir.getAbsolutePath() + File.separatorChar + date.getTime();
			ZipUsingJavaUtil zipUtils = new ZipUsingJavaUtil();
			zipUtils.unzip(zipFile, unzipDir);
			return new File(unzipDir);
		}
		return null;
	}
	
	private void processForm(File fileSrc,Long companyCampaignID,String pollName,Long localID)
	{
		PollService pollService = new PollService();
		Poll poll = pollService.getPollByName(pollName.replace(".xls", ""));	
		if(poll != null)
		{
			Workbook wb = POIUtils.getWorkbook(fileSrc);
			List<PollValue> listaValoresEncuesta = pollService.getPollValues(poll.getId(), companyCampaignID,localID);
			
			for(PollValue valorEncuesta : listaValoresEncuesta)
			{
				CellXLEW cellXLEW = new CellXLEW(valorEncuesta.getPollDefinition().getCode());
				String value = POIUtils.getCellValue(wb, cellXLEW);
				if(value != null)
				{	
					valorEncuesta.setValue(value.replace(".", "").replace(",", ".").replace(".0", ""));
				}
			}
			try {
				pollService.savePollValues(listaValoresEncuesta,sessionUserID,PollService.POLL_STATUS_EDITED);
			} catch (ExDBException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void cleanTempDirectory(File directory)
	{
		File[] files = directory.listFiles();
		for(File file : files)
		{
			if(file.isDirectory())
			{
				Utils.deleteDirectory(file);
			}
			else
			{
				file.delete();
			}
		}
	}
	
	private void generateForm(CompanyPoll companyPoll, File directorySrc)
	{
		String pollsPath = this.getServletContext().getRealPath(String.valueOf(File.separatorChar)) + "pollsXLS" + File.separatorChar;		
		String pollName = companyPoll.getPoll().getName().replace("\"", "") + ".xls";
		
		File fileSrc = new File(pollsPath + pollName);
		File fileDst = new File(directorySrc.getAbsolutePath() + File.separatorChar + pollName);
		try {
			Utils.copyFile(fileSrc, fileDst);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//LOGICA PARA LLENAR LAS CARATULAS
		
		PollService pollService = new PollService();
		List<CoverDefinition> coverDefinitionsList = pollService.getCoverDefinitionsByPoll(companyPoll.getPoll().getId());
		if(coverDefinitionsList != null && coverDefinitionsList.size() > 0)
		{
			Workbook wb = POIUtils.getWorkbook(fileDst);
			int i = 0;
			
			List<Country> countries = pollService.getCountries();
			String[] countriesC = new String[countries.size()];
			int ei = 0;
			for(Country country : countries)
			{
				countriesC[ei] = country.getCountry();
				ei++;
			}
			List<MiningItem> miningItems = pollService.getMiningItems();
			String[] miningItemsC = new String[miningItems.size()];			
			ei = 0;
			for(MiningItem miningItem : miningItems)
			{
				miningItemsC[ei] = miningItem.getDescription();
				ei++;
			}
			for(CoverDefinition coverDef : coverDefinitionsList)
			{
				CellXLEW xlewCell = new CellXLEW(coverDef.getCode());
				if(coverDef.getTable().equals(PollService.LOCAL_TABLE))
				{
					POIUtils.setCellValue(wb, xlewCell, companyPoll.getLocal().getAttribute(coverDef.getField()));
				}
				else if(coverDef.getTable().equals(PollService.COMPANY_TABLE))
				{
					POIUtils.setCellValue(wb, xlewCell, companyPoll.getCompanyCampaign().getCompany().getAttribute(coverDef.getField()));
				}
				else if(coverDef.getTable().equals(PollService.LIST_VALUES))
				{
					if(coverDef.getField().equals(PollService.LIST_COUNTRY))
					{
						xlewCell = new CellXLEW(coverDef.getCode());
						POIUtils.validateCell(xlewCell, countriesC, wb, i);
						i++;
					}
					else if(coverDef.getField().equals(PollService.LIST_MINNING))
					{						
						xlewCell = new CellXLEW(coverDef.getCode());
						POIUtils.validateCell(xlewCell, miningItemsC, wb, i);
						i++;
					}
				}
			}
			OutputStream os = null;
			try {
				os = new FileOutputStream(fileDst);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			try {
				wb.write(os);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private File getPackage(Long companyCampaignID)
	{
		String tempPath = this.getServletContext().getRealPath(
				String.valueOf(File.separatorChar))
				+ TEMP_DIRECTORY
				+ File.separatorChar
				+ DOWNLOAD_DIRECTORY
				+ File.separatorChar;

		Date date = new Date();
		File tempDir = new File(tempPath);
		if(!tempDir.exists() || !tempDir.isDirectory())
		{
			return null;
			//TODO ERROR NO EXISTEN LOS DIRECTORIOS
		}
		else
		{
			cleanTempDirectory(tempDir);
			ZipUsingJavaUtil zipUtils = new ZipUsingJavaUtil();			
			//CREO EL DIRECTORIO		
			String dirPackageStr = tempDir.getAbsolutePath() + File.separatorChar + date.getTime() + File.separatorChar + PACK_NAME;
			File dirCompany = new File(tempDir.getAbsolutePath() + File.separatorChar + date.getTime() + File.separatorChar + PACK_NAME +  File.separatorChar + "Empresa");
			File dirLocals = new File(tempDir.getAbsolutePath() + File.separatorChar + date.getTime() + File.separatorChar + PACK_NAME + File.separatorChar + "Locales");			
						
			try {
				dirCompany.mkdirs();
				dirLocals.mkdirs();
			} catch (Exception e) {
				e.printStackTrace();
			}
			//
			
			PollService pollService = new PollService();
			List<CompanyPoll> companyPolls = pollService.getCompanyPolls(companyCampaignID, new Long[] {
					PollService.POLL_E_ID, PollService.POLL_PB_ID,
					PollService.POLL_EPN_ID });
			
			if(companyPolls != null && companyPolls.size() > 0)
			{
				for(CompanyPoll companyPoll : companyPolls)
				{
					generateForm(companyPoll,dirCompany);
				}
			}
			else
			{
				//TODO NO ESTAN LAS ENCUESTAS EN LA BASE DE DATOS -MOSTRAR MENSAJE-
			}
			
			List<LocalMenu> pollLocals = pollService.getMenuLocalsByCompany(companyCampaignID);	
			
			if(pollLocals != null && pollLocals.size() > 0)
			{
				for(LocalMenu localMenu : pollLocals)
				{
					File dirLocal = new File(dirLocals.getAbsolutePath() + File.separatorChar + "Local " + localMenu.getLocal().getId());
					dirLocal.mkdirs();
					try {
						for(CompanyPoll companyPoll : localMenu.getAnnexes())
						{
							generateForm(companyPoll,dirLocal);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
			zipUtils.zipFiles(dirPackageStr, tempPath + "Paquete de Encuestas ("+ date.getTime() +").zip");
			File zipFile = new File(tempPath + "Paquete de Encuestas ("+ date.getTime() +").zip");
			return zipFile;
		}
	}
	
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		executeAction(req, resp);
	}
	
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		executeAction(req, resp);
	}
}
